package com.vivimice.lotroller;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.vivimice.lotroller.device.AndGate;
import com.vivimice.lotroller.device.Device;
import com.vivimice.lotroller.device.InputDevice;
import com.vivimice.lotroller.device.NotGate;
import com.vivimice.lotroller.device.OrGate;
import com.vivimice.lotroller.device.OutputDevice;
import com.vivimice.lotroller.notification.NotificationAgent;
import com.vivimice.lotroller.notification.NotificationType;

public abstract class Lotroller {

	private NotificationAgent agent;
	private List<Device> devices = new ArrayList<Device>();

	public Lotroller(NotificationAgent agent) {
		if (agent == null) {
			throw new NullPointerException();
		}
		this.agent = agent;
		onCreate();
	}

	public Lotroller(Lotroller parent) {
		this(parent.getAgent());
	}

	protected abstract void onCreate();
	
	protected abstract void onClose();
	
	public void close() {
		closeDevices();
		onClose();
	}

	protected NotificationAgent getAgent() {
		return agent;
	}
	
	protected Device in(NotificationType positiveType) {
		return new InputDevice(agent, positiveType);
	}
	
	protected Device in(NotificationType positiveType, NotificationType negativeType) {
		return new InputDevice(agent, positiveType, negativeType);
	}
	
	protected void out(NotificationType positiveType, Device device) {
		addDevice(new OutputDevice(device, agent, positiveType));
	}
	
	protected void out(NotificationType positiveType, NotificationType negativeType, Device device) {
		addDevice(new OutputDevice(device, agent, positiveType, negativeType));
	}
	
	protected Device and(Device ... devices) {
		return new AndGate(devices);
	}
	
	protected Device or(Device ... devices) {
		return new OrGate(devices);
	}
	
	protected Device not(Device device) {
		return new NotGate(device);
	}
	
	private void closeDevices() {
		Iterator<Device> itor = devices.iterator();
		while (itor.hasNext()) {
			itor.next().close();
			itor.remove();
		}
	}
	
	private void addDevice(Device device) {
		devices.add(device);
	}
	
}
